#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time    : 2021/12/14 10:27 上午
# @Author  : WangZhixing

import configparser
import os
import json


class ConfigFile:
    def __init__(self, path):
        self.path = path

    def ReadConfig(self):
        # 判断是选择使用哪个模型
        '''
        主要有4种不同的配置文件
        1、半监督学习配置文件
        2.1、无监督学习配置文件（节点为文件）
        2.2、无监督学习配置文件（节点为文件）NodeGCN模型
        2.3、无监督学习配置文件（节点为符号）
        Returns:
        {配置a：配置值a,}
        '''

        cf = configparser.ConfigParser()
        cf.read(self.path)  # 读取配置文件，如果写文件的绝对路径，就可以不用os模块
        if cf.has_option("Model", "type"):
            train_type = cf.get("Model", "type")
            if train_type.startswith("un"):
                return self.Read_unSurpervised_Config()
            else:
                return self.Read_semi_Surpervised_Config()

    # 读取半监督学习的配置文件
    def Read_semi_Surpervised_Config(self):
        cf = configparser.ConfigParser()
        cf.read(self.path)  # 读取配置文件，如果写文件的绝对路径，就可以不用os模块
        kwarg = {}

        # 数据存储的位置
        if cf.has_option("Data", "path"):
            kwarg['root'] = cf.get("Data", "path")

        # 数据存储的类别
        if cf.has_option("Data", "project"):
            kwarg['project'] = cf.get("Data", "project")

        # 判断是选择使用哪个模型
        # 判断模型的类别是半监督还是无监督
        # 训练轮数
        if cf.has_option("Model", "epochs"):
            kwarg['train_epoch'] = int(cf.get("Model", "epochs"))

        # 算法中间的中间层数，以及输出层数
        if cf.has_option("Model", "model_layer"):
            kwarg['model_layer'] = json.loads(cf.get("Model", "model_layer"))

        # 将结果输出的路径
        if cf.has_option("Output", "path"):
            kwarg['outfile_path'] = cf.get("Output", "path")
        else:
            kwarg['outfile_path'] = os.path.join(kwarg['root'], "processed", "result.rsf")

        # 使用cpu还是gpu
        if cf.has_option("Device", "device"):
            kwarg['device'] = cf.get("Device", "device")
        # 使用cpu还是gpu
        if cf.has_option("Model", "hidden_layer"):
            kwarg['hidden_layer'] = json.loads(cf.get("Model", "hidden_layer"))
        if cf.has_option("Model", "out_layer"):
            kwarg['out_layer'] = json.loads(cf.get("Model", "out_layer"))

        # ground_truth的路径，默认是None
        if cf.has_option("Metric", "ground_truth_path"):
            kwarg["ground_path"] = cf.get("Metric", "ground_truth_path")
        else:
            kwarg["ground_path"] = None

        if cf.has_option("optimizer","lr"):
            kwarg["lr"] = float(cf.get("optimizer", "lr"))
        return kwarg


    def Read_unSurpervised_Config(self):
        # 读取无监督学习的配置文件
        '''
        无监督学习使用的是类似与Node2vec的一个算法
        所以需要使用的参数比较多
        '''
        cf = configparser.ConfigParser()
        cf.read(self.path)  # 读取配置文件，如果写文件的绝对路径，就可以不用os模块
        kwarg = {}
        # 数据存储的位置
        if cf.has_option("Data", "path"):
            kwarg['root'] = cf.get("Data", "path")

        # 项目名称
        if cf.has_option("Data", "project"):
            kwarg['project'] = cf.get("Data", "project")

        # 数据存储的类别symbol还是文件
        if cf.has_option("Data", "type"):
            kwarg['data_type'] = cf.get("Data", "type")


        # 判断模型的类别是半监督还是无监督
        if cf.has_option("Model", "type"):
            kwarg['train_type'] = cf.get("Model", "type")

        # 训练轮数
        if cf.has_option("Model", "epochs"):
            kwarg['train_epoch'] = int(cf.get("Model", "epochs"))

        # 算法中间的中间层数，以及输出层数
        if cf.has_option("Model", "model_layer"):
            kwarg['model_layer'] = json.loads(cf.get("Model", "model_layer"))

        # 将结果输出的路径
        if cf.has_option("Output", "path"):
            kwarg['outfile_path'] = cf.get("Output", "path")

        # 聚类的聚类数目
        if cf.has_option("Output", "cluster"):
            kwarg['cluster'] = int(cf.get("Output", "cluster"))

        # 输出的方法。这里是指如果使用的是symbol；是使用average进行最终的embedding，还是使用vote？
        if cf.has_option("Output", "method"):
            kwarg['out_method'] = cf.get("Output", "method")

        # 使用cpu还是gpu
        if cf.has_option("Device", "device"):
            kwarg['device'] = cf.get("Device", "device")

        # ground_truth的路径，默认是None
        if cf.has_option("Metric", "ground_truth_path"):
            kwarg["ground_path"] = cf.get("Metric", "ground_truth_path")
        else:
            kwarg["ground_path"] = None
        if cf.has_option("optimizer","lr"):
            kwarg["lr"] = float(cf.get("optimizer", "lr"))

        # 是否用了node2vec的随机游走来作为loss function
        if cf.has_section("NodeGcn"):
            kwarg.update(self.Read_randomwalk_Config())
        return kwarg

    def Read_randomwalk_Config(self):
        '''
        读取node2vec_gcn的参数
        Node2Vec(data.edge_index,
        embedding_dim=128, #参数的配置在"Model", "model_layer"中最后的参数。
        walk_length=20,
        context_size=10, walks_per_node=10,
        num_negative_samples=1,
        p=1,
        q=1,
        sparse=True)
        '''
        cf = configparser.ConfigParser()
        cf.read(self.path)  # 读取配置文件，如果写文件的绝对路径，就可以不用os模块
        kwarg = {}
        # walk_length
        if cf.has_option("NodeGcn", "walk_length"):
            kwarg['walk_length'] = int(cf.get("NodeGcn", "walk_length"))
        # context_size
        if cf.has_option("NodeGcn", "context_size"):
            kwarg['context_size'] = int(cf.get("NodeGcn", "context_size"))

        # walks_per_node
        if cf.has_option("NodeGcn", "walks_per_node"):
            kwarg['walks_per_node'] = int(cf.get("NodeGcn", "walks_per_node"))

        # p
        if cf.has_option("NodeGcn", "p"):
            kwarg['p'] = float(cf.get("NodeGcn", "p"))

        # q
        if cf.has_option("NodeGcn", "q"):
            kwarg['q'] = float(cf.get("NodeGcn", "q"))

        # 算法中间的中间层数，以及输出层数
        if cf.has_option("NodeGcn", "num_negative_samples"):
            kwarg['num_negative_samples'] = int(cf.get("NodeGcn", "num_negative_samples"))
        return kwarg


if __name__ == '__main__':
    path = "/Users/wzx/Downloads/module-reverse-by-gnn/config/example/semi_Surpervised_Config.ini"
    a = ConfigFile(path)
    print(a.ReadConfig())

    path="/Users/wzx/Downloads/module-reverse-by-gnn/config/example/unSurpervised_Config.ini"
    a = ConfigFile(path)
    print(a.ReadConfig())

    path="/Users/wzx/Downloads/module-reverse-by-gnn/config/example/NodeGcn_unSurpervised_Config.ini"
    a = ConfigFile(path)
    print(a.ReadConfig())

    path="/Users/wzx/Downloads/module-reverse-by-gnn/config/example/symbol_unSurpervised_Config.ini"
    a = ConfigFile(path)
    print(a.ReadConfig())



